package com.cloudtech.multidownload.service;

import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.LinkedHashMap;
import java.util.Map;

import android.annotation.SuppressLint;
import android.app.Service;
import android.content.Intent;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.text.TextUtils;
import android.util.Log;

import com.cloudtech.multidownload.MultiDownloadManager;
import com.cloudtech.multidownload.entitis.FileInfo;
import com.cloudtech.multidownload.util.Logger;
import com.cloudtech.multidownload.util.SSLUtils;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLSocketFactory;


@SuppressLint("HandlerLeak")
public class DownloadService extends Service {

    public static final String ACTION_START = "ACTION_START";
    public static final String ACTION_STOP = "ACTION_STOP";
    public static final String ACTION_UPDATE = "ACTION_UPDATE";
    public static final String ACTION_FINISHED = "ACTION_FINISHED";
    public static final String ACTION_ERROR = "ACTION_ERROR";
    public static final String ACTION_DESTORY = "ACTION_DESTORY";

    public static final int MSG_INIT = 0;

    private Map<Integer, DownloadTask> mTasks = new LinkedHashMap<Integer, DownloadTask>();

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public void onCreate() {
        super.onCreate();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Logger.log("start service intent:" + intent + ",id:" + startId);
        if (intent != null) {
            if (ACTION_START.equals(intent.getAction())) {
                FileInfo fileInfo = (FileInfo) intent.getSerializableExtra("fileInfo");
                InitThread initThread = new InitThread(fileInfo);
                DownloadTask.sExecutorService.execute(initThread);
            } else if (ACTION_STOP.equals(intent.getAction())) {
                FileInfo fileInfo = (FileInfo) intent.getSerializableExtra("fileInfo");
                DownloadTask task = mTasks.get(fileInfo.getId());
                if (task != null) {
                    task.mIsPause = true;
                }
            } else if (ACTION_DESTORY.equals(intent.getAction())) {
                destory();
                stopSelf(startId);
            }
        }
        return super.onStartCommand(intent, flags, startId);
    }

    Handler mHandler = new Handler() {
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case MSG_INIT:
                    FileInfo fileInfo = (FileInfo) msg.obj;
                    DownloadTask task = new DownloadTask(DownloadService.this, fileInfo, fileInfo.getThreadCount());
                    task.download();
                    mTasks.put(fileInfo.getId(), task);
                    Intent intent = new Intent(ACTION_START);
                    intent.putExtra("fileInfo", fileInfo);
                    sendBroadcast(intent);
                    break;
            }
        }

        ;
    };

    class InitThread extends Thread {
        private FileInfo mFileInfo = null;
        private HttpURLConnection conn = null;
        private RandomAccessFile raf = null;

        public InitThread(FileInfo mFileInfo) {
            super();
            this.mFileInfo = mFileInfo;
        }

        @Override
        public void run() {

            try {
                String url = mFileInfo.getUrl();
                handleConnection(url);

            } catch (Exception e) {
                mFileInfo.setError(true);
                if (mFileInfo.isAutoRetry()) {
                    MultiDownloadManager.startDownloadFile(getApplicationContext(), mFileInfo);
                } else {
                    Intent intent = new Intent(DownloadService.ACTION_ERROR);
                    intent.putExtra("fileInfo", mFileInfo);
                    sendBroadcast(intent);
                }
                Logger.log("get http err:" + Log.getStackTraceString(e));
            } finally {
                if (conn != null) {
                    conn.disconnect();
                }
                try {
                    if (raf != null) {
                        raf.close();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            super.run();
        }


        private void handleConnection(String url) throws IOException {
            Logger.log("DownloadService >> handleConnection >> url >>> " + url);

            URL finalUrl = new URL(url);
            conn = (HttpURLConnection) finalUrl.openConnection();

            if (conn instanceof HttpsURLConnection) {
                SSLSocketFactory sslSocketFactory = SSLUtils.defaultSSLSocketFactory();
                ((HttpsURLConnection) conn).setSSLSocketFactory(sslSocketFactory);
                HostnameVerifier hostnameVerifier = SSLUtils.defaultHostnameVerifier();
                if (hostnameVerifier != null) {
                    ((HttpsURLConnection) conn).setHostnameVerifier(hostnameVerifier);
                }
            }
            String userAgent = System.getProperty("http.agent");
            if (!TextUtils.isEmpty(userAgent)){
                conn.setRequestProperty("User-Agent", userAgent);
            }
            conn.setConnectTimeout(mFileInfo.getTimeOut() * 1000);
            conn.setReadTimeout(20 * 1000);
            conn.setRequestMethod("GET");
            int code = conn.getResponseCode();
            Logger.log("DownloadService >> http code:" + code);
            switch (code){
                case HttpURLConnection.HTTP_OK:
                    handle200(conn);
                    break;
                case HttpURLConnection.HTTP_MOVED_PERM:
                case HttpURLConnection.HTTP_MOVED_TEMP:
                    handle302(conn);
                    break;
            }



        }

        private void handle200(HttpURLConnection conn) throws IOException{
            Logger.log("DownloadService >> handle200 >>> ");
            int length = conn.getContentLength();

            if (length <= 0) {
                return;
            }
            File dir = new File(this.mFileInfo.getSaveDir());
            if (!dir.exists()) {
                dir.mkdir();
            }
            File file = new File(dir, mFileInfo.getFileName());
            raf = new RandomAccessFile(file, "rwd");
            raf.setLength(length);
            mFileInfo.setLength(length);
            Message msg = Message.obtain();
            msg.obj = mFileInfo;
            msg.what = MSG_INIT;
            mHandler.sendMessage(msg);

        }

        private void handle302(HttpURLConnection conn) throws IOException{
            Logger.log("DownloadService >> handle302 >>> ");
            String location = conn.getHeaderField("Location");
            handleConnection(location);
        }


    }

    @Override
    public void onDestroy() {
        Logger.log("service destory!");
        destory();
        super.onDestroy();
    }

    private void destory() {
        if (mTasks != null && mTasks.size() > 0) {
            for (int id : mTasks.keySet()) {
                mTasks.get(id).mIsPause = true;
                mTasks.get(id).destory();
            }
        }
    }
}